package org.NooLab.glue.subscription;

import java.util.Vector;

import org.NooLab.compare.utilities.math.DistanceControlProperties;
import org.NooLab.glue.instances.ParticipantsDeliveryPad;
import org.NooLab.glue.msgframe.BasicMessageParams;
import org.NooLab.glue.msgframe.FXMessage;
import org.NooLab.glue.msgframe.XRegistration;
import org.NooLab.utilities.logging.PrintLog;
import org.NooLab.utilities.net.GUID;



/**
 * 
 * 
 * - define Future objects
 * - get a list, filtered by properties (like age)
 * - publish(), publish(id)
 * - unpublish(id), unpublish(Future), unpublishAll()
 * 
 * 
 * the MessageBoardFactory 
 * 
 */
public class Futures implements FuturesIntf{
	
	ParticipantsDeliveryPad deliveryPad; 
	
	Vector<Future> futures = new Vector<Future>();
	
	
	XRegistration xRegistration;
	String roleOfParticipant;
	
	FXMessage xmsg ;
	
	PrintLog out ;
	
	public Futures( XRegistration xreg, PrintLog outprn ){
		
		xRegistration = xreg ;
		out = outprn;
		
		roleOfParticipant = xRegistration.getRole() ;
		
		xmsg = new FXMessage(out);
	}
	
	public Futures( PrintLog outprn ){
		
		out = outprn;
		xmsg = new FXMessage(out);
	}	
	
	public int size(){
		
		if (futures==null){
			futures = new Vector<Future>();
			return 0;
		}
		
		return futures.size() ;
	}
	
	public int size(long instanceID) {
		Vector<Future> futuresById;
		
		futuresById = getFuturesById(instanceID,0);
		
		return futuresById.size();
	}
		
	@Override
	public int size(int type, long instanceID) {
		Vector<Future> futuresById;
		futuresById = getFuturesById(instanceID,type);
		return futuresById.size();
	}

	public String add( FutureIntf futur ){
		String sindex = GUID.randomvalue() ;
		 
		// the participants receive a new GUID, while the MessageBoard on re-establishing
		// the future on its side should NOT create a new GUID
		if (futur.getGuid().length()<=1){
			futur.setGuid(sindex) ;
		}
		
		// casting the intf back to the object is possible here in this context 
		futures.add( (Future)futur) ;
		
		return sindex;
	}

	@Override
	public FutureIntf create( DistanceControlProperties distancectrl ) {
		 
		Future future;
		
		 
		future = new Future( distancectrl );
		
		return future;
	}

 
	
	private Future  getFutureByGuid( String guid ){
		Future  fut=null;
		String fguid;
		
		for (int i=0;i<futures.size();i++){
			
			fguid = futures.get(i).getGuid();
			
			if (fguid.contentEquals(guid)){
				fut = futures.get(i);
				break;
			}
		}
		
		return fut;
	}
	
	public Vector<Future> getFuturesById( long instanceID){
		return getFuturesById( instanceID, -1);
	}
	
	public Vector<Future> getFuturesById( long instanceID, int type){
		
		Vector<Future> futuresById = new Vector<Future> ();
		int t;
		Future future;
		FutureProperties  props;
		
		
		for (int i=0;i<futures.size();i++){
			
			future = futures.get(i) ;
			if ( (instanceID == future.getInstanceID()) &&
				 (future.getProperties().size()>0)){
				
				props = future.getProperties().get(0) ;
				t = props.getType() ;
				if ((t==type) || (type<=0)){ // FutureProperties._CONTEXT
					futuresById.add(future);
				}
			}
		}// i->
		
		return futuresById;
	}
	
	@Override
	public int publish(String subguid) {
		int r=-1;
		
		Future future=null;
		String xmlstr="";
		long iid;
		
		if (xRegistration==null){
			// in case of MessageBoard's futures...
			return 3;
		}
		try{
			
		/*
 			<messageboard name="spela" role="SOURCE">
   				<subscription action="define">
      				<instance id="2528" name="" />
      				
      				<properties id="85313bb1-17c6-47ca-bf14-7ced92d03d46" type="1">   type=1 == plain, 2==context
      				
      					<property id="0" label="keywords">
      						<items type="incl" values="a;b;c;d"/>
      						<items type="excl" values="x"/>
      					</property>
      					
      					<property id="1" label="match" >
      						<items type="threshold" value="0.71">
      					</property>
      				
   					</properties>
   				</subscription>
			</messageboard>
		*/
			future = getFutureByGuid( subguid ) ;
			
			// now creating a xml representation of it     
			  
			BasicMessageParams basics = new BasicMessageParams();

			basics.instanceID = xRegistration.getInstanceID() ;
			basics.instanceName = xRegistration.getNameOfApplicant() ;
			basics.roleOfSender = roleOfParticipant ;
			basics.privateTransactionIdentifier = subguid;
			
			if ((future!=null) && (future.properties.size()>0) ){
				
				int fstype = future.properties.get(0).type ;
				
				xmsg.setDistanceControlProperties( future.distanceCtrl ) ;
				
				if (fstype == FutureProperties._SIMPLESET){
					xmlstr = xmsg.createXmlFromFutureSimple( future, basics, "define" ) ;
				} 
				
				if (fstype == FutureProperties._VECTOR){
					xmlstr = xmsg.createXmlFromFutureFeatureVector( future, basics, "define" ) ;
				}
				
				if (fstype == FutureProperties._CONTEXT){
					xmlstr = xmsg.createXmlFromFutureCtxt( future, 1, basics, "define" ) ;
				}
				if (fstype == FutureProperties._STRING){
					
				}
				if (fstype == FutureProperties._FREETEXT){
					xmlstr = xmsg.createXmlFromFutureFullText( future, basics, "define" ) ;
				}
				if (fstype == FutureProperties._IMAGE){
					
				}
			}
			
			// and sending it to the MessageBoard, using DataConnector 
			
			if ((xRegistration!=null) && (xmlstr.trim().length()>10)){
				
				iid = xRegistration.getInstanceID();
				future.instanceID = iid; // as participant, this is constant for all accessible futures,
										 // yet, we need it for querying the list of futures
				
				xRegistration.announceSubscription(xmlstr) ;
				r=0;
			} else{
				r = -3;
			}
			
		}catch(Exception e){
			
		}
		
		return r;
	}

	@Override
	public int unpublish(String subguid) {
		 
		Future future;
		int r;
		String xmlstr;
		
		/*
			<messageboard name="spela" role="SOURCE">
				<subscription action="unpublish" name="85313bb1-17c6-47ca-bf14-7ced92d03d46" >
  					<instance id="2528" />
				</subscription>
		    </messageboard>
	    */
		try {
			future = getFutureByGuid(subguid);

			// now creating a xml representation of it

			BasicMessageParams basics = new BasicMessageParams();

			basics.instanceID = xRegistration.getInstanceID();
			basics.instanceName = xRegistration.getNameOfApplicant();
			basics.roleOfSender = roleOfParticipant;
			basics.privateTransactionIdentifier = subguid;

			xmlstr = xmsg.createXmlForUnpublishingFuture(future, basics, "unpublish");

			// and sending it to the MessageBoard, using DataConnector

			if (xRegistration != null) {
				xRegistration.announceSubscription(xmlstr); // that's a simple send without confirmation
				out.print(2, "request for unpublishing a subscription (id:"+subguid+") has been sent.");
				remove(subguid) ;
				r = 0;
			} else {
				r = -3;
			}

		} catch (Exception e) {
			e.printStackTrace() ;
		}

		 

		return 0;
	}

	
	@Override
	public int remove(String subguid) {
		
		Future future ;
		String fuid;
		
		if (futures==null){
			futures = new Vector<Future>();
			return 0;
		}
		for (int i=0;i<futures.size();i++){
			
			future = futures.get(i) ;
			if (future!=null){
				fuid = future.getGuid();
				if (fuid.contentEquals(subguid)){
					futures.remove(i) ;
					break;
				}
			}
			
		} // i->
		int n = futures.size() ; 
		return n;
	}

	
	
	@Override
	public int removeAll(long instanceID) {
		
		Future future ;
		int i;
		
		if (futures==null){
			futures = new Vector<Future>();
			return 0;
		}
		
		i=futures.size()-1; 
		while (i>=0){
			future = futures.get(i) ;
			if ((future!=null) && (future.instanceID == instanceID)){
				futures.remove(i) ;
			}
			i--;
		} // i->0
		int n = futures.size() ; 
		return n;
	}

	/**
	 * the index is relative to the entries for instanceID
	 * 
	 */
	@Override
	public int remove(long instanceID, int index) {
		 
		Future future ;
		int i,ix=0;
		
		if (futures==null){
			futures = new Vector<Future>();
			return 0;
		}
		
		 
		for (i=0;i<futures.size();i++){
			future = futures.get(i) ;
			if ((future!=null) && (future.instanceID == instanceID)){
				if (ix==index){
					futures.remove(i) ;
					break;
				}else{
					ix++;
				}
			}
			
		} // i->
		
		
		int n = futures.size() ; 
		return n;
	}

 
	
	
	// ========================================================================



	public void setSender( ParticipantsDeliveryPad deliverypad ){
		deliveryPad = deliverypad;
	}
	
	
	// ------------------------------------------------------------------------
	
	public String getRoleOfParticipant() {
		return roleOfParticipant;
	}

	public void setRoleOfParticipant(String roleOfParticipant) {
		this.roleOfParticipant = roleOfParticipant;
	}

}
